package com.zmm.util.auth.interceptor;

import com.alibaba.fastjson.JSON;
import com.zmm.common.base.model.Result;
import com.zmm.common.base.model.ResultCode;
import com.zmm.common.redis.key.CommonKey;
import com.zmm.util.auth.constant.AuthConstant;
import com.zmm.util.auth.filter.AuthFilter;
import com.zmm.util.auth.model.AuthParam;
import com.zmm.util.auth.model.Operator;
import com.zmm.util.auth.model.UserForAuth;
import com.zmm.util.redis.RedisUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

/**
 * @author 900045
 * @description:
 * @name AbstractAuthInterceptor
 * @date By 2021-07-06 09:33:04
 */
public abstract class AbstractAuthInterceptor implements AuthInterceptor {

	protected Logger logger   = LoggerFactory.getLogger(this.getClass());

	@Resource
	protected Operator operator;

	private List<AuthFilter> preFilters;

	@Resource
	private RedisUtil<Object> redisUtil;

	private String checkMsg = null;

	@Override
	public boolean doPreHandle(AuthParam param, Object handler) {
		String url = param.getRequest().getRequestURI();
		if (!(handler instanceof HandlerMethod)) {
			logger.error("{} is a =============> {}", url, handler);
			// 不匹配就返回true
			return true;
		}
		HandlerMethod method = (HandlerMethod) handler;
		param.setPath(param.getRequest().getRequestURI());
		//前缀过滤器
		boolean filter = this.doPreFilter(method, param);
		if (!filter) {
			return returnResp(param.getResponse(), Result.error(ResultCode.NOT_LOGGED));
		}

		UserForAuth user = loadUser(param.getRequest());
		//用户为空
		if (user == null) {
			// 用户为空 判断是否允许 匿名访问
			if (param.isCanAnon()){
				return true;

			} else {
				return returnResp(param.getResponse(), Result.error(ResultCode.NOT_LOGGED));
			}

		} else {
			return true;
		}
	}

	private UserForAuth loadUser(HttpServletRequest request) {

		// 1.校验token  从请求头中获取 token字符串，
		String token = request.getHeader(AuthConstant.HEADER_TOKEN_KEY);
		// 2.从 redis 中获取
		Object object = getUserFromRedis(token);
		if (object == null){
			return null;
		}

		if (object == null || !(object instanceof UserForAuth)) {
			logger.error("AUTH-GET-USER null: {}, {}", object, object);
			return null;
		}

		UserForAuth user = (UserForAuth) object;
		// 3.放入userId 到当前线程
		operator.addThread(user);
		logger.debug("AUTH-TOKEN: {} -> {}: url:{}", token, user, request.getRequestURI());
		return user;

	}

	/**
	 * 清理当前线程信息
	 * @author: 900045
	 * @date: 2021-06-04 16:35:12
	 * @throws

	 * @return: void
	 **/
	protected void doClean() {
		operator.clean();
	}

	/**
	 * 从缓存中获取 用户信息
	 * @author: 900045
	 * @date: 2021-06-04 16:29:36
	 * @throws
	 * @param token: 
	 * @return: java.lang.Object
	 **/
	public Object getUserFromRedis(String token){

		// 判断参数是否为空
		if (StringUtils.isEmpty(token)) {
			return null;
		}
		// 从redis中获取 此token对应用的用户 然后保存在当前线程中
		// Object o = redisTemplate.opsForValue().get(Constant.TOKEN_USER + token)
		// redisUtil.get(Constant.TOKEN_USER + token)
		Object key = redisUtil.get(CommonKey.AUTH_TOKEN_USER_PREFIX.setSuffix(token));
		if (key == null) {
			return null;
		}
		Object o = redisUtil.hash(CommonKey.AUTH_USER_KEY, key);

		if (o == null) {
			return null;
		}
		return o;
	}

	protected boolean returnResp(HttpServletResponse response, Result result) {
		response.setCharacterEncoding("UTF-8");
		response.setContentType("application/json; charset=utf-8");
		logger.info("REQ-INTERCEPTOR-BASE:{}", result);
		try (PrintWriter writer = response.getWriter();) {
			writer.print(JSON.toJSONString(result));
			writer.flush();
		} catch (IOException e) {
			logger.error("response error", e);
		}
		return false;
	}


	/**
	 * 添加前缀过滤器
	 * @author: 900045
	 * @date: 2021-06-07 10:23:14
	 * @throws
	 * @param filter: 
	 * @return: void
	 **/
	public void addPreFilter(AuthFilter filter) {
		if (preFilters == null) {
			preFilters = new ArrayList<>();
		}
		preFilters.add(filter);
	}


	/**
	 * 前置过滤器 -- 执行到不通过的一个为止
	 * @author: 900045
	 * @date: 2021-06-07 10:24:17
	 * @throws
	 * @param method: 
	 * @param param: 
	 * @return: boolean
	 **/
	private boolean doPreFilter(HandlerMethod method, AuthParam param) {
		if (CollectionUtils.isEmpty(preFilters)) {
			return true;
		}
		for (AuthFilter authFilter : preFilters) {
			if (!authFilter.doFilter(method, param)) {
				logger.error("do pre filter fail ======> {}", param.getPath());
				return false;
			}
		}

		return true;
	}

	protected boolean checkResp(HttpServletResponse response,String serviceName) {
		//仅仅是校验redis  是否可用
		redisUtil.exists(CommonKey.DICT_VERSION_KEY);
		if (checkMsg == null) {
			checkMsg = String.format("%s checkup succeed!", serviceName.replace("service-", ""));
		}
		return returnResp(response, Result.ok(checkMsg));
	}
	
}
